package com.asm.blog.shiro;

import cn.hutool.core.bean.BeanUtil;
import com.asm.blog.entity.User;
import com.asm.blog.service.UserService;
import com.asm.blog.util.JwtUtils;
import io.jsonwebtoken.Claims;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component // 注解为一个 bean，交给spring容器管理
public class AccountRealm extends AuthorizingRealm {
    private Logger log = LoggerFactory.getLogger(AccountRealm.class);
    /**
     * 要求 支持强转 条件
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    // 注入 jwt工具类 和 用户服务层
    @Autowired
    JwtUtils jwtUtils;
    @Autowired
    UserService userService;

    /**
     * 授权方法
     * @param principal
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {

        log.info(">>>>>>>>>> 授权器：MyRealm.doGetAuthorizationInfo >>>>>>>>>>>>");
        final SimpleAuthorizationInfo orization = new SimpleAuthorizationInfo();

        final Object o = principal.asList().get(0);
        log.info("principal.asList().get(0)" + o.toString());

        // 数据表里 查 此人的 角色权限
        orization.addRoles(Arrays.asList("admin"));
//        orization.addStringPermissions(user.getUserPerms());

        return orization;
    }

    /**
     *
     *------------------------------------------------------------
     *                                                           /
     *                        <b>认证 方法 </b>                   /
     *   根据 jwt验证 并获取 用户，返回给SimpleAuthenticationInfo    /
     *   进一步传递用户信息 和 验证登录                              /
     *                                                           /
     * ===========================================================
     *
     * 流程---->
     *      *  用户访问需要登录的 uri 时
     *      *      先 JwtFilter [ preHandle()                 ->
     *      *      onAccessDenied(){ executeLogin(执行登录) }  ->
     *      *      createToken() ]                            ->
     *      *      ......                                     ->
     *      *      当前方法
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        // 1. 强转为 JwtToken
        JwtToken jwt = (JwtToken) token;

        /**
         * 2. 从token里获取用户ID
         *    (String)jwt.getPrincipal()                                 就是获取token 但是要转为String
         *    jwtUtils.getClaimByToken( (String)jwt.getPrincipal() )     是 Claims类型，  里面的 getSubject() 通常就是获取ID的
         *
         */
        String userId = jwtUtils.getClaimByToken( (String)jwt.getPrincipal() ).getSubject();

        // 3. 获取用户对象
        User user = userService.getById(Long.valueOf(userId));

        // 4. 判断 账户 不存在 和 锁定
        if(user == null)
        {
            throw new UnknownAccountException("账户不存在了啊");
        }else if (user.getStatus() == -1)
        {
            throw new LockedAccountException("账户已被锁定");
        }


        // 5. 返回的一般都是 公开的信息， 私密信息不返回 ，所以 拷贝创建 可公开的账户对象
        AccountProfile profile = new AccountProfile();
        BeanUtil.copyProperties(user, profile);

        // 6. 返回 给 shiro 登录

        return new SimpleAuthenticationInfo(profile, jwt.getCredentials(), getName());
    }
}
